package com.ai.bitcoin.jpa.service;

import com.ai.bitcoin.exception.BusinessException;
import com.ai.bitcoin.jpa.dao.*;
import com.ai.bitcoin.jpa.entity.*;
import com.ai.bitcoin.utils.HttpClientUtils;
import com.ai.bitcoin.vo.BoomBustQueueVO;
import com.ai.bitcoin.vo.BuyerQueueVo;
import com.ai.bitcoin.vo.ErcTwoZeroQueueVO;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Service
@Slf4j
public class BccArticleService {
    @Autowired
    BccArticleDao bccArticleDao;
    @Autowired
    BccBasicInfoDao bccBasicInfoDao;
    @Autowired
    BccNewsDao bccNewsDao;
    @Autowired
    CoinNews2BccDao coinNews2BccDao;
    @Autowired
    CoinAnno2BccDao coinAnno2BccDao;
    @Autowired
    BccAnnoInfoCrawlDao bccAnnoInfoCrawlDao;


    /**
     * 根据条件查找文章
     *
     * @param bccIdList       bcc列表
     * @param articleTypeList 类型列表
     * @param articleTypeList 类型列表
     * @param pageRequest     页面请求
     * @return 文章列表
     */
    public Page<BccArticle> findByBccInfo(List<String> bccIdList, List<String> articleTypeList, List<String> tagList, PageRequest pageRequest) {

        Page<BccArticle> page = bccArticleDao.findAll((Specification<BccArticle>) (root, query, cb) -> {
            List<Predicate> predicateList = Lists.newArrayList();
            if (CollectionUtils.isNotEmpty(bccIdList)) {
                predicateList.add(root.get("bccId").as(String.class).in(bccIdList));
            }
            if (CollectionUtils.isNotEmpty(articleTypeList)) {
                predicateList.add(root.get("articleType").as(String.class).in(articleTypeList));
            }
            if (CollectionUtils.isNotEmpty(tagList)) {
                predicateList.add(root.get("tagList").as(String.class).in(tagList));
            }
            return cb.and(predicateList.toArray(new Predicate[0]));
        }, pageRequest);
        for (BccArticle article : page) {
            BccBasicInfo bccBasicInfo = bccBasicInfoDao.findByBccId(article.getBccId());
            article.setSymbol(bccBasicInfo.getSymbol());
        }
        return page;
    }


    @Transactional
    @CacheEvict(value = "articleSearch", allEntries = true)
    public void syncAnnoData(int startPage, int batchSize) {
        //最近1000条交易所数据
        Page<CoinAnno2Bcc> annoPage = coinAnno2BccDao.findAllAnno(PageRequest.of(startPage, batchSize, Sort.by(Sort.Direction.DESC, "updateTime")));
        for (CoinAnno2Bcc srcArticle : annoPage) {
            BccAnnoInfoCrawl annoInfo = srcArticle.getAnno();
            BccBasicInfo bccInfo = srcArticle.getBccInfo();
            if (annoInfo == null || bccInfo == null) {
                srcArticle.setSynced(true);
                continue;
            }
            BccArticle article
                    = bccArticleDao.findByBccIdAndUniqueKey(srcArticle.getBccInfo().getBccId(), annoInfo.getId());
            if (article == null) {
                article = new BccArticle();
            }
            article.setUniqueKey(annoInfo.getAnnoId());
            article.setBccId(bccInfo.getBccId());
            article.setBatchNo(srcArticle.getBatchNo());
            article.setArticleType("01");
            article.setSourceDomain(annoInfo.getCrawlFromDomian());
            article.setSourceUrl(HttpClientUtils.getShortUrl(annoInfo.getAnnoUrl()));
            article.setTitle(StringUtils.substring(annoInfo.getTitle(), 0, 64));
            article.setTagList(annoInfo.getTagList());
            article.setDescription(annoInfo.getDescription());
            //如果标题为空 截取内容前64个字符
            if (StringUtils.isEmpty(article.getTitle())) {
                article.setTitle(StringUtils.substring(annoInfo.getDescription(), 0, 64));
            }
            ;
            article.setCreateTime(annoInfo.getCreateTime());
            article.setSpeechUrl(HttpClientUtils.getShortUrl(annoInfo.getSpeechUrl()));
            article.setUpdateTime(new Date());

            bccArticleDao.save(article);

            srcArticle.setSynced(true);
        }
        coinAnno2BccDao.saveAll(annoPage);
    }

    @Transactional
    @CacheEvict(value = "articleSearch", allEntries = true)
    public void syncNewsData(int startPage, int batchSize) {
        //最近1000条交易所数据
        Page<CoinNews2Bcc> newsPage = coinNews2BccDao.findAllNews(PageRequest.of(startPage, batchSize, Sort.by(Sort.Direction.DESC, "updateTime")));
        for (CoinNews2Bcc coinNews2Bcc : newsPage) {
            BccNews news = coinNews2Bcc.getNews();
            BccBasicInfo bccInfo = coinNews2Bcc.getBccInfo();
            if (news == null || bccInfo == null) {
                coinNews2Bcc.setSynced(true);
                continue;
            }
            BccArticle article
                    = bccArticleDao.findByBccIdAndUniqueKey(bccInfo.getBccId(), news.getId());
            if (article == null) {
                article = new BccArticle();
            }
            article.setUniqueKey(news.getId());
            article.setBccId(bccInfo.getBccId());
            article.setArticleType("02");
            article.setBatchNo(article.getBatchNo());
            article.setSourceDomain(news.getCrawlFromDomian());
            article.setSourceUrl(HttpClientUtils.getShortUrl(news.getNewsUrl()));
            article.setTitle(StringUtils.substring(news.getTitle(), 0, 64));

            article.setBearCount(NumberUtils.toInt(news.getBearCount()));
            article.setBullCount(NumberUtils.toInt(news.getBullCount()));

            //如果标题为空 截取内容前64个字符
            if (StringUtils.isEmpty(article.getTitle())) {
                article.setTitle(StringUtils.substring(news.getDescription(), 0, 64));
            }

            article.setTagList(news.getTagList());
            article.setSpeechUrl(HttpClientUtils.getShortUrl(news.getSpeechUrl()));
            article.setDescription(news.getDescription());
            article.setCreateTime(news.getCreateTime());
            article.setUpdateTime(new Date());
            bccArticleDao.saveAndFlush(article);

            coinNews2Bcc.setSynced(true);
            coinNews2BccDao.saveAndFlush(coinNews2Bcc);
        }
    }


    @Scheduled(cron = "* 0/5 * * * ?")
    @Transactional
    public void syncAnnoDataScheduled() {
        syncAnnoData(0, 50);
    }

    @Scheduled(cron = "* 0/3 * * * ?")
    @Transactional
    public void syncNewsDataScheduled() {
        syncNewsData(0, 30);
    }

    @Cacheable("articleDetail")
    public BccArticle getOne(String articleId) {
        Optional<BccArticle> articleOptional = bccArticleDao.findById(articleId);
        return articleOptional.get();
    }

    @CachePut(value = "articleDetail", key = "#articleId")
    public BccArticle updateCount(String articleId, String countType) throws BusinessException {
        BccArticle article = getOne(articleId);
        if (article == null) {
            throw new BusinessException("400", "不存在");
        }

        if (StringUtils.equals(countType, "01")) {
            article.setBullCount(article.getBullCount() + 1);
        }
        if (StringUtils.equals(countType, "02")) {
            article.setBearCount(article.getBearCount() + 1);
        }
        article = bccArticleDao.save(article);
        return article;
    }

    //保存暴涨暴跌信息
    public void saveBoomBust(Long id, BoomBustQueueVO bustQueueVO) {
        try {
            BccArticle article = new BccArticle();
            BccBasicInfo bcc = bccBasicInfoDao.findByBccId(bustQueueVO.getBcc_id());
            if (bcc == null) {
                return;
            }
            String title = MessageFormat.format("当前{0}在{1}的价格：¥{2}， 5分钟内变化幅度超过{3}%，价格下降¥{4}，价格波动较大，请密切关注行情走向，做好风险控制。"
                    , bcc.getSymbol()
                    , bustQueueVO.getMarket()
                    , bustQueueVO.getPrice()
                    , bustQueueVO.getPrice_change_rate().abs()
                    , (bustQueueVO.getPrice().compareTo(bustQueueVO.getPrice_previous()) > 0 ? "上涨" : "下降") +
                            (bustQueueVO.getPrice().subtract(bustQueueVO.getPrice_previous()).abs())
            );
            article.setUniqueKey(String.valueOf(id));
            article.setBccId(bustQueueVO.getBcc_id());
            article.setArticleType("03");
            article.setBatchNo(article.getBatchNo());
            article.setTitle(title);
            article.setDescription(title);
            article.setTagList("暴涨暴跌," + StringUtils.defaultString(bcc.getNameEn()) + "," + StringUtils.defaultString(bcc.getNameCn()));
            article.setCreateTime(new Date());
            article.setUpdateTime(new Date());
            bccArticleDao.save(article);
        } catch (Exception e) {
            log.warn("暴涨暴跌保存Article失败 {}", bustQueueVO);
        }
    }

    //保存ERC20信息
    public void saveErc20(String id, ErcTwoZeroQueueVO ercTwoZeroQueueVO) {
        try {
            BccArticle article = new BccArticle();
            BccBasicInfo bcc = bccBasicInfoDao.findByBccId(ercTwoZeroQueueVO.getBcc_id());
            if (bcc == null) {
                return;
            }
            article.setUniqueKey(id);
            article.setBccId(ercTwoZeroQueueVO.getBcc_id());
            article.setArticleType("04");
            article.setBatchNo(article.getBatchNo());
            article.setTitle(MessageFormat.format("监控到{0}于{1}发生一大笔大额转账 "
                    , bcc.getSymbol()
                    , DateFormatUtils.format(new Date(Long.valueOf(ercTwoZeroQueueVO.getTransfer_time()) * 1000), "yyyy-MM-dd HH:mm:ss")
            ));

            String fromName = StringUtils.isNotEmpty(ercTwoZeroQueueVO.getFrom_name()) ? "(" + ercTwoZeroQueueVO.getFrom_name() + ")" : "";
            String toName = StringUtils.isNotEmpty(ercTwoZeroQueueVO.getTo_name()) ? "(" + ercTwoZeroQueueVO.getTo_name() + ")" : "";
            article.setDescription("转账金额：" + ercTwoZeroQueueVO.getVolume() + "\n" +
                    "\n" +
                    "占流通比例：" + ercTwoZeroQueueVO.getCirculationPercent() + "%\n" +
                    "\n" +
                    "转出地址：" + ercTwoZeroQueueVO.getFrom_address() + fromName + "\n" +
                    "\n" +
                    "转入地址： " + ercTwoZeroQueueVO.getTo_address() + toName
            );
            article.setTagList("大额转账" + "," + "ERC20" + "," + StringUtils.defaultString(bcc.getNameEn()) + "," + StringUtils.defaultString(bcc.getNameCn()));
            article.setCreateTime(new Date());
            article.setUpdateTime(new Date());
            bccArticleDao.save(article);
        } catch (Exception e) {
            log.warn("大额转账保存Article失败 {}", ercTwoZeroQueueVO, e);
        }
    }

    //保存卖点信息
    public void saveBuySellPoint(long id, BuyerQueueVo buyerQueueVo) {
        try {
            BccArticle article = new BccArticle();
            BccBasicInfo bcc = bccBasicInfoDao.findByBccId(buyerQueueVo.getBcc_id());
            if (bcc == null) {
                return;
            }

            article.setUniqueKey(String.valueOf(id));
            article.setBccId(buyerQueueVo.getBcc_id());
            article.setArticleType("05");
            article.setBatchNo(article.getBatchNo());
            article.setTitle(MessageFormat.format("监控到{0}达到买点卖点"
                    , bcc.getSymbol()
                    , buyerQueueVo.getTime()
            ));

            article.setDescription(MessageFormat.format("当前{0}价格为¥{1}，预测压力位¥{2}，预测支撑位{3} 目前已经到达最佳买点／卖点"
                    , bcc.getSymbol()
                    , buyerQueueVo.getCurrent_rate()
                    , buyerQueueVo.getLow_bound()
                    , buyerQueueVo.getUp_bound()
                    )
            );
            article.setTagList("买点卖点," + StringUtils.defaultString(bcc.getNameEn()) + "," + StringUtils.defaultString(bcc.getNameCn()));
            article.setCreateTime(new Date());
            article.setUpdateTime(new Date());
            bccArticleDao.save(article);
        } catch (Exception e) {
            log.warn("买点卖点保存Article失败 {}", buyerQueueVo, e);
        }
    }

}
